package noyau;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/** Classe chargee d'interpreter le fichier de configuration.
 *
 */

public class Configuration {

    /** Structure qui associe à chaque identifiant le nom de la classe. */
    private final Map < String, String > declarations;

    /**
     * Un liste de couples d'identifiants
     */
    private final List < ArrayList < String > > branchements;

    /**
     * le chemin vers le fichier journal
     */
    private String fichierlog;

    /**
     * Une référence vers le logger noyau
     */
    private static final Logger LOG = Logger.getLogger("noyau");

    /**
     * Constructeur par défaut
     */
    public Configuration() {
        this.declarations = new HashMap < String, String >();
        this.branchements = new ArrayList < ArrayList < String > >();
        this.fichierlog = "noyau.log"; // par défaut
    }

    /**
     * Prend une ligne du fichier de conf et affecte
     * les attributs en conséquence
     * @param ligne la ligne elle-même
     * @param section la section du fichier de conf
     *        où on l'a trouvée (1, 2 ou 3)
     */
    private void interpreterLigne(final String ligne, final int section) {

        final int secDeclaration = 1;
        final int secArchitecture = 2;
        final int secFichierLog = 3;

        switch (section) {
            case secDeclaration :
                final String cle = ligne.substring(0, ligne.indexOf(':'));
                final String val = ligne.substring(ligne.lastIndexOf(':') + 1,
                                                   ligne.length());
                this.declarations.put(cle, val);
                break;
            case secArchitecture :
                // on récupère ce qu'il y a à gauche et à droite de '-'
                final String gauche = ligne.substring(0, ligne.indexOf('-'));
                final String droite = ligne.substring(ligne.lastIndexOf('-')
                                                          + 1,
                                                      ligne.length());
                final ArrayList < String > listeParsee =
                                                   new ArrayList < String >();
                listeParsee.add(gauche);
                listeParsee.add(droite);
                this.branchements.add(listeParsee);
                break;
            case secFichierLog :
                this.fichierlog = ligne;
                break;
            default :
                // erreur de le fichier :-(
        }
    }

    /**
     * charger la configuration depuis un fichier
     * @param chemin le chemin vers le fichier de configuration
     * @return vrai si le fichier a bien pu etre lu
     * @throws FileNotFoundException
     */
    public final boolean chargerDepuisFichier(final String chemin)
                                       throws FileNotFoundException {
        try {
            final BufferedReader fichier = new BufferedReader(
                                                       new FileReader(chemin));
            String ligne;
            boolean finDuFichier = false;
            int section = 1;
            do {
                ligne = fichier.readLine();
                if (ligne.charAt(0) == '/') {
                    // '/' délimite la fin du fichier, on sort de la boucle
                    finDuFichier = true;
                } else if (ligne.charAt(0) == '=') {
                    // '=' est le délimiteur, on passe à la section suivante
                    ++section;
                } else if (ligne.charAt(0) != '#') {
                    // cas de base, selon la section dans laquelle on se trouve
                    this.interpreterLigne(ligne, section);
                }
            } while (ligne != null && !finDuFichier);
        } catch (FileNotFoundException e) {
            LOG.log(Level.WARNING, "Impossible de trouver le fichier "
                                   + chemin);
            throw e;
        } catch (IOException e) {
            LOG.log(Level.WARNING, "Erreur lors de la lecture du fichier "
                                   + chemin);
        }
        return true;
    }

    /**
     * Otenir tous les identifiants des plugins branchs au plugin
     * dont l'identifiant est pass en paramtre
     * @param identifiant l'identifiant du plugin dont on veut les connectés
     * @return des identifiants de plugins
     */
    public final List < String > getConnectes(final String identifiant) {
        final List < String > resultat = new ArrayList < String >();
        for (ArrayList < String > branchement : branchements) {
            if (branchement.get(0).equals(identifiant)) {
                resultat.add(branchement.get(1));
            } else if (branchement.get(1).equals(identifiant)) {
                resultat.add(branchement.get(0));
            }
        }
        return resultat;
    }

    /**
     * Tous les identifiants dclars
     * @return l'ensemble de identifiants
     */
    public final Set < String > getDeclares() {
        return declarations.keySet();
    }

    /**
     * Obtenir le nom de la classe associe  un identifiant
     * @param identifiant l'identifiant
     * @return le nom de la classe
     */
    public final String getNomClasse(final String identifiant) {
        return declarations.get(identifiant);
    }

    /**
     * Vérifie la cohérence du fichier de configuration
     * On retourne faux si, dans l'architecture, un plug-in
     * utilisé n'est pas déclaré
     * @return vrai si le fichier est cohérent, faux sinon
     */
    public final boolean verificationFichier() {
        boolean resultat = true;
        for (List < String > p : branchements) {
            for (String identifiant : p) {
                if (!declarations.containsKey(identifiant)) {
                    resultat = false;
                }
            }
        }
        return resultat;
    }

    /**
     * @return le chemin vers le fichier journal
     */
    public final String getFichierlog() {
        return fichierlog;
    }
}
